package container

import (
	"fmt"
	"log"
	"os"
	"text/tabwriter"

	"gitee.com/chuanjinge/go-container/container/vethbr"
)

// 创建网桥类型的网络
func CreateBridgeNetwork(name string, subnet string) error {
	br := &vethbr.BridgeDriver{}
	nw, err := br.Create(subnet, name) // 该动作会同时分配 gatewayIP
	if err != nil {
		return err
	}
	// 落盘
	list, err := vethbr.NewNetworkList()
	if err != nil {
		return err
	}

	return list.Add(nw)
}

// 列出所有的网络
func ListNetwork() error {
	networks, err := vethbr.NewNetworkList()
	if err != nil {
		return err
	}

	// 通过tabwriter库把信息打印到屏幕上
	w := tabwriter.NewWriter(os.Stdout, 12, 1, 3, ' ', 0)
	fmt.Fprint(w, "NAME\tIpRange\tDriver\n")
	for _, net := range networks.List() {
		fmt.Fprintf(w, "%s\t%s\t%s\n",
			net.Name,
			net.IPRange.String(),
			net.Driver,
		)
	}
	if err = w.Flush(); err != nil {
		log.Printf("Flush error %v\n", err)
		return err
	}
	return nil
}

func RemoveNetwork(netName string) error {
	networks, err := vethbr.NewNetworkList()
	if err != nil {
		return err
	}

	nw, exist := networks.Exist(netName)
	if !exist {
		return fmt.Errorf("网络%s不存在", netName)
	}

	// 删除掉与当前bridge相关的SNAT信息，DNAT不删除因为DNAT还与容器的ip:port相关
	// 比如：iptables -t nat -A POSTROUTING -s 172.20.0.0/24 ! -o br0 -j MASQUERADE
	//      其中 [! -o bro] 表示的是出口不是bro的
	// 删除方法：把 -A(add) 改为 -D(delete) 就可以了
	//    iptables -t nat -D POSTROUTING -s 192.168.88.0/24 ! -o babykxtten -j MASQUERADE
	if err := vethbr.DeleteIPTableSNAT(netName, nw.IPRange); err != nil {
		log.Printf("[error]删除网络:%s的SNAT信息失败", netName)
	}

	// 关于网桥在路由中的信息，即 ip route 中 dev为当前网络设备的路由配置。
	// 在centos8下这些路由信息都会随着网桥的删除而自动消息，所以不管了
	// 这种路由配置有两种情况：
	// - 删除网桥的时候，之前自动添加到系统中的路由信息，会自动被删除，不用显示调用（我在centos8测试是这样子）
	// -- 如下所示为kernel自动添加的路由信息，所有发往 192.168.88 段的请求都会被设备babykxtten承接，源IP设置为192.168.88.1
	// [root@k8s-node-demo container]#  ip route
	// 192.168.88.0/24 dev babykxtten proto kernel scope link src 192.168.88.1
	//
	// -- 如果有自动添加的路由信息依赖 babykxtten 进行转发的。
	// -- 比如有人添加了如下的route:
	// -- ip route add 192.168.99.0/24 via 192.168.88.254 dev babykxtten
	// -- 我们希望 192.168.99.0 段的请求通过babykxtten转发到192.168.88.254，因为254这个机器我们用来作为一个独立网关。
	br := &vethbr.BridgeDriver{}
	if err := br.Delete(&nw); err != nil {
		return err
	}

	return networks.Remove(netName)
}
